home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Tools & Apps / Graphics & Imaging / Virtual Sphere 1.0 / Graphics3D.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-14  |  12.9 KB  |  407 lines  |  [TEXT/MPS ]

  1. /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  2. /* Graphics3D.c
  3. /*
  4. /* 3D graphics and math routines
  5. /*
  6. /* Author: Michael Chen, Human Interface Group / ATG
  7. /* Copyright © 1991-1992 Apple Computer, Inc.  All rights reserved.
  8. /*
  9. /* Part of Virtual Sphere Sample Code Release v1.0
  10. /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••*/
  11.  
  12. #ifndef    __GRAPHICS3D__
  13. #include "Graphics3D.h"
  14. #endif
  15.  
  16. #ifndef __FIXMATH__
  17. #include <FixMath.h>
  18. #endif
  19.  
  20. #ifndef __LIMITS__
  21. #include <Limits.h>
  22. #endif
  23.  
  24. #ifndef __RESOURCES__
  25. #include <Resources.h>
  26. #endif
  27.  
  28. #ifndef __MEMORY__
  29. #include <Memory.h>
  30. #endif
  31.  
  32. #ifndef __ERRORS__
  33. #include <Errors.h>
  34. #endif
  35.  
  36. #include "Sample.h"
  37.  
  38. /* Structure used for dithering patterns */
  39. typedef struct {
  40.     short    patListSize;    /* Size */
  41.     Pattern    patList[1];        /* Pointer to varible size arrary */
  42. } **PatListHandle;
  43.  
  44. /* Local globals for this file (module) only */
  45. static ConstPatternParam    lgPolyShade;
  46. static PatListHandle        lgDitherPatterns = nil;
  47.  
  48.  
  49. /*=================================================================================================
  50. /* InitializeGraphics3D
  51. /*-------------------------------------------------------------------------------------------------*/
  52. pascal OSErr InitializeGraphics3D ()
  53. {
  54.     OSErr err;
  55.     
  56.     /* Load in dither patterns for black and white drawing. */
  57.     if (lgDitherPatterns == nil) {
  58.         lgDitherPatterns = (PatListHandle) GetResource ('PAT#', rDitherPatterns);
  59.         if (lgDitherPatterns == nil) return (resNotFound);
  60.  
  61.         /* Move the dithering pattern as high up in memory as possible and 
  62.          * and lock it down.  */
  63.         DetachResource ((Handle) lgDitherPatterns);    if ((err = MemError()) != noErr) return (err);
  64.         MoveHHi        ((Handle) lgDitherPatterns);    if ((err = MemError()) != noErr) return (err);
  65.         HNoPurge       ((Handle) lgDitherPatterns);    if ((err = MemError()) != noErr) return (err);
  66.         HLock          ((Handle) lgDitherPatterns);    if ((err = MemError()) != noErr) return (err);
  67.     }
  68.     return (noErr);
  69. }
  70.  
  71. /*=================================================================================================
  72. /* FreeGraphics3D
  73. /*-------------------------------------------------------------------------------------------------*/
  74. pascal void FreeGraphics3D ()
  75. {
  76.     /* Dispose the memeory used for the dither patterns  */
  77.     if (lgDitherPatterns == nil) {
  78.         DisposeHandle ((Handle) lgDitherPatterns);
  79.     }
  80. }
  81.  
  82. /*=================================================================================================
  83. /* CopyMatrix
  84. /*-------------------------------------------------------------------------------------------------*/
  85. typedef struct {        /* Struct to make matrix copying more efficient */
  86.     Matrix4D a;
  87. } MatrixAsStruct;
  88.  
  89. pascal void CopyMatrix (Matrix4D fromMatrix, Matrix4D toMatrix)
  90. {
  91.     * (MatrixAsStruct *) toMatrix = * (MatrixAsStruct *) fromMatrix;
  92. }
  93.  
  94. /*=================================================================================================
  95. /* CrossProduct3D
  96. /*
  97. /* Returns the right-handed cross product of a and b in c
  98. /*-------------------------------------------------------------------------------------------------*/
  99. pascal void CrossProduct3D (const CPoint3D *a, const CPoint3D *b, CPoint3D *aCrossB)
  100. {
  101.     aCrossB->x = a->y * b->z - a->z * b->y;
  102.     aCrossB->y = a->z * b->x - a->x * b->z;
  103.     aCrossB->z = a->x * b->y - a->y * b->x;
  104. }
  105.  
  106. /*=================================================================================================
  107. /* DrawPolyNet
  108. /*
  109. /* Draws a PolyNet object with different backfaced polygon removal and rendering options.
  110. /*-------------------------------------------------------------------------------------------------*/
  111. pascal void DrawPolyNet (const PolygonNetData *polyNet)
  112. {
  113.     Point3D        *vertices;            /* local index into the vertex array */
  114.     Integer        *vertexIndices;
  115.     Integer        i;
  116.     
  117.     if (polyNet->fVertexCount < 0) DebugMessage ("\pfVertexCount < 0");
  118.  
  119.     vertices = polyNet->fVertices;
  120.     vertexIndices = polyNet->fVertexIndices;
  121.     
  122.     /* For each polygon... */
  123.     for (i = 0; i < polyNet->fPolygonCount; i++) {
  124.         Integer firstVertexIndex;
  125.         NetPolygon *thisPoly = &polyNet->fPolys[i];
  126.         if (thisPoly->fVertexCount < 3) continue;    /* This is not a polygon.  Skip to next one. */
  127.         firstVertexIndex = thisPoly->fFirstVertexIndex;
  128.  
  129.         if (gDoBackfacedPolygonRemoval) {
  130.             /* Transform first 3 points to screen coordinate to do backface polygon test.
  131.              * Code will not work if any vertex is offscreen!
  132.              */
  133.             Point p0, p1, p2;
  134.             Integer v1h, v1v, v2h, v2v;
  135.             
  136.             MoveTo3D (vertices [vertexIndices [firstVertexIndex  ]].x,
  137.                       vertices [vertexIndices [firstVertexIndex  ]].y,
  138.                       vertices [vertexIndices [firstVertexIndex  ]].z);
  139.             GetPen (&p0);
  140.             MoveTo3D (vertices [vertexIndices [firstVertexIndex+1]].x,
  141.                       vertices [vertexIndices [firstVertexIndex+1]].y,
  142.                       vertices [vertexIndices [firstVertexIndex+1]].z);
  143.             GetPen (&p1);
  144.             MoveTo3D (vertices [vertexIndices [firstVertexIndex+2]].x,
  145.                       vertices [vertexIndices [firstVertexIndex+2]].y,
  146.                       vertices [vertexIndices [firstVertexIndex+2]].z);
  147.             GetPen (&p2);
  148.  
  149.             v1h = p1.h - p0.h;
  150.             v1v = p1.v - p0.v;
  151.             v2h = p2.h - p1.h;
  152.             v2v = p2.v - p1.v;
  153.  
  154.             /* Check for backfaced polygon by doing cross-product.  Skip if backfaced.
  155.              * Try using '<=' test instead to get the inside-out effect */
  156.             if ((v1h * v2v - v1v * v2h) >= 0) continue;
  157.         }
  158.  
  159.         {
  160.             /* Draw the polygon */
  161.             
  162.             PolyHandle    polyHdl = nil;
  163.             Integer j;
  164.             Integer vertexIndex;
  165.  
  166.             if (gRenderingStyle != iLineDrawing) {
  167.                 /* gRenderingStyle is iFlatShading or iFlatShadingWithOutline.
  168.                  * Begin collecting QD polygon */
  169.                 polyHdl = OpenPoly ();
  170.             }
  171.             PolyColor (&polyNet->fColor [thisPoly->fColorIndex]);
  172.             
  173.             /* Initial move */
  174.             vertexIndex = vertexIndices [firstVertexIndex];
  175.             MoveTo3D    (    vertices [vertexIndex].x,
  176.                             vertices [vertexIndex].y,
  177.                             vertices [vertexIndex].z);
  178.             /* Hit the vertices */                
  179.             for (j = firstVertexIndex+1; j < firstVertexIndex+thisPoly->fVertexCount; j++){
  180.                 vertexIndex = vertexIndices [j];
  181.                 LineTo3D(    vertices [vertexIndex].x,
  182.                             vertices [vertexIndex].y,
  183.                             vertices [vertexIndex].z);
  184.             }
  185.             /* Close the polygon */
  186.             vertexIndex = vertexIndices [firstVertexIndex];
  187.             LineTo3D    (    vertices [vertexIndex].x,
  188.                             vertices [vertexIndex].y,
  189.                             vertices [vertexIndex].z);
  190.             
  191.             if (gRenderingStyle != iLineDrawing) {
  192.                 ClosePoly ();                                  /* Stop collecting QD polygon */
  193.                 FillPoly (polyHdl, lgPolyShade);
  194.                 if (gRenderingStyle == iFlatShadingWithOutline) {
  195.                     ForeColor (blackColor);
  196.                     FramePoly (polyHdl);
  197.                 }
  198.                 KillPoly (polyHdl);
  199.             }
  200.         }
  201.     }
  202. }
  203.  
  204. /*=================================================================================================
  205. /* Length3D
  206. /*
  207. /* Returns the length of vector a 
  208. /*-------------------------------------------------------------------------------------------------*/
  209. pascal Real Length3D (const CPoint3D *a)
  210. {
  211.     return (sqrt (a->x*a->x + a->y*a->y + a->z*a->z));
  212. }
  213.  
  214. /*=================================================================================================
  215. /* Matrix2XfMatrix
  216. /*
  217. /* Converts a Matrix4D to a XfMatrix used by Graf3D
  218. /*-------------------------------------------------------------------------------------------------*/
  219. pascal void Matrix2XfMatrix (Matrix4D fromMatrix, XfMatrix toMatrix)
  220. {
  221.     Integer i, j;
  222.     
  223.     for (i=3; i>=0; i--) {
  224.         for (j=3; j>=0; j--) {
  225.             toMatrix[i][j]= Real2Fix (fromMatrix[i][j]);
  226.         }
  227.     }
  228.  
  229. #ifdef xxxxxxxxxxxxxxxxxxxxxxxxxNOT_USEDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  230.     /* Faster but kludgy version of the same thing */
  231.     
  232.     Real    *fromPtr = (Real  *) fromMatrix;
  233.     Fixed    *toPtr   = (Fixed *) toMatrix;
  234.     Integer i;
  235.     for (i=15; i>=0; i--) {
  236.         *toPtr++ = Real2Fix (*fromPtr++);
  237.     }
  238. #endif xxxxxxxxxxxxxxxxxxxxxxxxxNOT_USEDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  239. }
  240.  
  241. /*=================================================================================================
  242. /* MultiplyMatrix
  243. /*
  244. /* Matrix multiplication c = a x b 
  245. /*-------------------------------------------------------------------------------------------------*/
  246. pascal void MultiplyMatrix (Matrix4D a, Matrix4D b, Matrix4D aTimesB)
  247. {
  248.     Integer i, j, k;
  249.  
  250.     for (i=3; i>=0; i--) {
  251.         for (j=3; j>=0; j--) {
  252.             Real sum = 0.0;
  253.             for (k=3; k>=0; k--) {
  254.                 sum += a[i][k] * b[k][j];
  255.             }
  256.             aTimesB[i][j]= sum;
  257.         }
  258.     }
  259. }
  260.  
  261. /*=================================================================================================
  262. /* Normalize3D
  263. /*
  264. /* Returns the normalized vector
  265. /*-------------------------------------------------------------------------------------------------*/
  266. pascal void Normalize3D (CPoint3D *v)
  267. {
  268.     Real length;
  269.  
  270.     length = sqrt (v->x * v->x + v->y * v->y + v->z * v->z);
  271.     if (length > 0) {
  272.         v->x /= length;
  273.         v->y /= length;
  274.         v->z /= length;
  275.     } else {
  276.         /* Vector is zero.  Probably should set some error */
  277.         v->x = v->y = v->z = 0;
  278.         DebugMessage ("\p Normalize3D: zero vector!");
  279.     }
  280. }
  281.  
  282. /*=================================================================================================
  283. /* OrthogonalizeRotationMatrix
  284. /*
  285. /* Orthogonalizes a pure rotation matrix (this is not checked!).
  286. /* Assumes the "y-axis" (2nd row) of the matrix is "correct"
  287. /* and make 1st and 3rd row orthogonal to it.
  288. /* Assumes matrix is already close to orthogonal.
  289. /*-------------------------------------------------------------------------------------------------*/
  290. pascal void OrthogonalizeRotationMatrix (Matrix4D matrix)
  291. {
  292.     CPoint3D xAxis, yAxis, zAxis;
  293.  
  294.     yAxis.x = matrix[1][0];
  295.     yAxis.y = matrix[1][1];
  296.     yAxis.z = matrix[1][2];
  297.     zAxis.x = matrix[2][0];
  298.     zAxis.y = matrix[2][1];
  299.     zAxis.z = matrix[2][2];
  300.  
  301.     Normalize3D (&yAxis);
  302.     UnitCrossProduct3D  (&yAxis, &zAxis, &xAxis);
  303.     UnitCrossProduct3D  (&xAxis, &yAxis, &zAxis);
  304.  
  305.     matrix[0][0] = xAxis.x;
  306.     matrix[0][1] = xAxis.y;
  307.     matrix[0][2] = xAxis.z;
  308.  
  309.     matrix[1][0] = yAxis.x;
  310.     matrix[1][1] = yAxis.y;
  311.     matrix[1][2] = yAxis.z;
  312.  
  313.     matrix[2][0] = zAxis.x;
  314.     matrix[2][1] = zAxis.y;
  315.     matrix[2][2] = zAxis.z;
  316. }
  317.  
  318. /*=================================================================================================
  319. /* PolyColor
  320. /*
  321. /* Given a RGB color, calls the appropriate QuickDraw routines to set up the
  322. /* appropriate drawing environment.  If gDrawInColor is false (because of a
  323. /* menu choice or color QD is not available) the color is replaced by a
  324. /* dithering pattern. 
  325. /*-------------------------------------------------------------------------------------------------*/
  326. pascal void PolyColor (const RGBColor *rGBColor)
  327. {
  328.     if (gDrawInColor) {
  329.         lgPolyShade = qd.black;
  330.         RGBForeColor (rGBColor);
  331.     } else {
  332.         /* Convert RGB to dither pattern.  Note we use different weighting factors
  333.          * for the RGB components  to come up with a grey value.  This is just 
  334.          * so that more different patterns are shown on the objects.  Note RGB components are shorts. */
  335.         Integer kMaxPatternIndex = (**lgDitherPatterns).patListSize;
  336.         unsigned long index;
  337.         unsigned long intensity;
  338.         #define    kRWeight        6
  339.         #define    kGWeight        4
  340.         #define    kBWeight        3
  341.         #define    kTotalWeight    (kRWeight + kGWeight + kBWeight)
  342.         intensity = kRWeight*rGBColor->red + kGWeight*rGBColor->green + kBWeight*rGBColor->blue;
  343.         index = intensity * kMaxPatternIndex / kTotalWeight / USHRT_MAX;    /* Note integer math.  Order matters */
  344.         if (index >= kMaxPatternIndex) index = kMaxPatternIndex -1;            /* Needed? */
  345.         lgPolyShade = (**lgDitherPatterns).patList [index];
  346.         ForeColor (blackColor);
  347.     }
  348. }
  349.  
  350. /*=================================================================================================
  351. /* SetRotationMatrix
  352. /*
  353. /* Computes s rotation matrix given the axis and amount of rotation.  The only rotation
  354. /* matrix you ever need.
  355. /* Source: Graphics Gems Vol. 1.  Andrew Glassner, Ed.  Addison-Wesley.
  356. /*-------------------------------------------------------------------------------------------------*/
  357. pascal void SetRotationMatrix (Matrix4D rotationMatrix, const CPoint3D *axis, Real radians)
  358. {
  359.     Real s, c, t;
  360.     
  361.     #define ax    (axis->x)
  362.     #define ay    (axis->y)
  363.     #define az    (axis->z)
  364.     #define ax2    (ax * ax)
  365.     #define ay2    (ay * ay)
  366.     #define az2    (az * az)
  367.  
  368.     s = sin (radians);
  369.     c = cos (radians);
  370.     t = 1 - c;
  371.  
  372.     rotationMatrix[0][0] = t*ax2+c;
  373.     rotationMatrix[0][1] = t*ax*ay+s*az;
  374.     rotationMatrix[0][2] = t*ax*az-s*ay;
  375.  
  376.     rotationMatrix[1][0] = t*ax*ay-s*az;
  377.     rotationMatrix[1][1] = t*ay2+c;
  378.     rotationMatrix[1][2] = t*ay*az+s*ax;
  379.  
  380.     rotationMatrix[2][0] = t*ax*az+s*ay;
  381.     rotationMatrix[2][1] = t*ay*az-s*ax;
  382.     rotationMatrix[2][2] = t*az2+c;
  383.  
  384.     rotationMatrix[0][3] = rotationMatrix[1][3] = rotationMatrix[2][3] = 
  385.     rotationMatrix[3][0] = rotationMatrix[3][1] = rotationMatrix[3][2] = 0.0;
  386.     rotationMatrix[3][3] = 1.0;
  387.  
  388.     #undef ax
  389.     #undef ay
  390.     #undef az
  391.     #undef ax2
  392.     #undef ay2
  393.     #undef az2
  394. }
  395.  
  396. /*=================================================================================================
  397. /* UnitCrossProduct3D
  398. /*
  399. /* Returns the normalized right-handed cross product of a and b in c
  400. /*-------------------------------------------------------------------------------------------------*/
  401. pascal void UnitCrossProduct3D (const CPoint3D *a, const CPoint3D *b, CPoint3D *aCrossB)
  402. {
  403.     CrossProduct3D (a, b, aCrossB);
  404.     Normalize3D (aCrossB);
  405. }
  406.  
  407.